//
//  StatzApplescriptPlugin.m
//  Statz
//
//  Created by Dave MacLachlan on 2007/12/07.
//  Copyright 2007 Google Inc. All rights reserved.
// 
// Licensed under the Apache License, Version 2.0 (the "License"); you may not
// use this file except in compliance with the License.  You may obtain a copy
// of the License at
// 
// http://www.apache.org/licenses/LICENSE-2.0
// 
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
// License for the specific language governing permissions and limitations under
// the License.
//

#import "StatzApplescriptPlugin.h"
#import "NSAppleEventDescriptor+Array.h"
#import "StatusUpdate.h"
#import "AEVTBuilder.h"

const OSType kAEStatzPluginSuite = 'St@P';

@interface StatzApplescriptPlugin (StatzApplescriptPluginPrivate)
- (NSAppleEventDescriptor*)doApplescriptWithID:(OSType)aeID;
@end

@implementation StatzApplescriptPlugin
- (id)initWithApplescript:(NSString*)scriptPath {
  if (!(self = [super init])) return nil;
  NSURL *url = [NSURL fileURLWithPath:scriptPath];
  NSDictionary *error = nil;
  script_ = [[NSAppleScript alloc] initWithContentsOfURL:url error:&error];
  if (!script_) {
    NSLog(@"Error loading script plugin:%@ (%@)", scriptPath, error);
    [self release];
    self = nil;
  }
  cachedValues_ = [[NSMutableDictionary alloc] init];
  scriptPath_ = [scriptPath copy];
  return self;
}

- (void)dealloc {
  [script_ release];
  [cachedValues_ release];
  [scriptPath_ release];
  [super dealloc];
}

// For an App based sink, return it's bundle ID.
- (NSString*)appBundleID {
  id value = [cachedValues_ objectForKey:@"kAppBundleKey"];
  if (!value) {
    value = [[self doApplescriptWithID:'PlBI'] stringValue];
    if (!value) {
      value = [NSNull null];
    }
    [cachedValues_ setObject:value forKey:@"kAppBundleKey"];
  }
  if (value == [NSNull null]) {
    value = nil;
  }
  return value;
}

- (NSString*)name {
  id value = [cachedValues_ objectForKey:@"kNameKey"];
  if (!value) {
    value = [[self doApplescriptWithID:'PlNa'] stringValue];
    if (!value) {
      value = [NSNull null];
      NSLog(@"Unable to get plugin name for: %@", scriptPath_);
    }
    [cachedValues_ setObject:value forKey:@"kNameKey"];
  }
  if (value == [NSNull null]) {
    value = nil;
  }
  
  if (!value) {
    NSString *appBundleID = [self appBundleID];
    if (appBundleID) {
      value = [super name];
    }
  }
  if (!value) {
    value = [[scriptPath_ lastPathComponent] stringByDeletingPathExtension];
  }
  return value;
}

- (NSImage*)image {
  id value = [cachedValues_ objectForKey:@"kImageKey"];
  if (!value) {
    NSString *imagePath = [[self doApplescriptWithID:'PlIm'] stringValue];
    if (!imagePath) {
      value = [NSNull null];
    } else {
      value = [[[NSImage alloc] initWithContentsOfFile:imagePath] autorelease];
      if (!value) {
        NSLog(@"Unable to load image at path: %@ for: %@", imagePath, scriptPath_);
      }
    }
    [cachedValues_ setObject:value forKey:@"kImageKey"];
  }
  if (value == [NSNull null]) {
    value = nil;
  }
  
  if (!value) {
    NSString *appBundleID = [self appBundleID];
    if (appBundleID) {
      value = [super image];
    }
  }
  
  if (!value) {
    value = [NSImage imageNamed:@"StatzAppleScript.icns"];
  }
  return value;
}

- (NSString*)uuid {
  id value = [cachedValues_ objectForKey:@"kUUIDKey"];
  if (!value) {
    value = [[self doApplescriptWithID:'PlUD'] stringValue];
    if (!value) {
      value = [NSNull null];
      NSLog(@"Unable to get plugin uuid for: %@", scriptPath_);
    }
    [cachedValues_ setObject:value forKey:@"kUUIDKey"];
  }
  if (value == [NSNull null]) {
    value = nil;
  }
  if (value == nil) {
    // Generate a UUID of some sort (we use path-creationdate)
    NSFileManager *fm = [NSFileManager defaultManager];
    NSDictionary *attribs = [fm fileAttributesAtPath:scriptPath_ traverseLink:YES];
    NSDate *creationDate = [attribs objectForKey:NSFileCreationDate];
    
    value = [NSString stringWithFormat:@"%@-%@", scriptPath_, [creationDate description]];
  }
  return value;
}

- (unsigned int)stateMenuMask {
  id value = [cachedValues_ objectForKey:@"kStateMaskKey"];
  if (!value) {
    NSAppleEventDescriptor *desc = [self doApplescriptWithID:'PlSt'];
    unsigned int state = kStatzStateNone;
    if (desc) {
      
      NSEnumerator *states = [[desc arrayValue] objectEnumerator];
      NSString *stateString;
      while ((stateString = [states nextObject])) {
        OSType rval = 0;
        NSData* data = [stateString dataUsingEncoding: NSMacOSRomanStringEncoding];
        [data getBytes:&rval length:sizeof(rval)];
        rval = OSSwapBigToHostInt32(rval);    
        StatzState newState = [StatzSource stateFromScriptState:rval];
        state |= newState;
      }
    }
    value = [NSNumber numberWithInt:state]; 
    [cachedValues_ setObject:value forKey:@"kStateMaskKey"];
  }
  return [value intValue];
}

- (void)scriptUpdateStatz:(StatusUpdate*)statusUpdate {
  NSDictionary *error = nil;
  NSAppleEventDescriptor *event = [AEVT class:kAEStatzPluginSuite
                                           id:'UpSt'
                               targetBundleID:[[NSBundle mainBundle] bundleIdentifier],
                                   [KEY:keyDirectObject], [STRING: [statusUpdate status]],
                                   [KEY:'Stae'], [ENUM: [statusUpdate state]],
                                   ENDRECORD];
  NSAppleEventDescriptor *desc = [script_ executeAppleEvent:event
                                                      error:&error];
  if (!desc || error) {
    NSLog(@"Error updating status from script %@. (%@)", scriptPath_, error);
     value_ = kStatzUpdateError;
  } else {
    OSType value = [desc enumCodeValue];
    switch(value) {
      case 'uSuc':
        value_ = kStatzUpdateSuccess;
        break;
        
      case 'uErr':
        value_ = kStatzUpdateError;
        break;
        
      case 'uNot':
        value = kStatzUpdateNotChanged;
        break;
        
      default:
        value_ = kStatzUpdateError;
        break;
    }
  }
}

- (StatzUpdateValue)updateStatz:(StatusUpdate*)statusUpdate {
  value_ = kStatzUpdateNotChanged;
  [self performSelectorOnMainThread:@selector(scriptUpdateStatz:) withObject:statusUpdate waitUntilDone:YES];
  return value_;
}

- (NSAppleEventDescriptor*)doApplescriptWithID:(OSType)aeID {
  NSAppleEventDescriptor *event = [AEVT class:kAEStatzPluginSuite
                                           id:aeID
                               targetBundleID:[[NSBundle mainBundle] bundleIdentifier],
                                        ENDRECORD];
  NSDictionary *error = nil;
  NSAppleEventDescriptor *desc = [script_ executeAppleEvent:event
                                                      error:&error];
  if (error) {
    desc = nil;
  }
  return desc;
}


@end
